package com.xinqi.common.mapstruct.convert;

import com.xinqi.common.base.data.IdNameDTO;
import com.xinqi.common.base.enums.BaseEnum;
import com.xinqi.common.base.enums.BasicEnum;
import com.xinqi.common.base.error.CommonErrors;
import com.xinqi.common.base.utils.date.Dates;
import com.xinqi.common.base.utils.lambda.Lambdas;
import org.apache.commons.lang3.StringUtils;
import org.mapstruct.TargetType;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * <ul>
 * <li>实现时间的映射 使用 unix timestamp, 秒级
 * <li>实现 IdNameDTO 的基本转换
 * <li>实现枚举的基本转换
 * <li>数字与布尔值互转
 * <li>集合转换为数字
 * </ul>
 *
 * @author linkai
 * @date 2022/11/25
 */
public interface BaseConvert {

    /**
     * Boolean转Integer
     */
    static Integer integerFromBoolean(Boolean s) {
        return Lambdas.apply(s, v -> v ? 1 : 0);
    }

    static Boolean booleanFromInteger(Integer s) {
        return Lambdas.apply(s, v -> v != 0);
    }

    static Long dateUnixTimestamp(Date s) {
        return Lambdas.apply(s, v -> v.getTime());
    }

    static Long localDateTime2Long(LocalDateTime dateTime) {
        return Dates.localDateTime2Long(dateTime);
    }

    static Long localDate2Long(LocalDate date) {
        return Dates.localDate2Long(date);
    }

    static Date dateFromUnixTimestamp(Long s) {
        return Lambdas.apply(s, v -> new Date(s));
    }

    static <T extends Enum<T>> Integer enumOrdinal(T s) {
        if (s == null) {
            return null;
        }
        if (s instanceof BasicEnum) {
            return ((BasicEnum) s).getCode();
        }
        return Lambdas.apply(s, Enum::ordinal);
    }

    static <T extends Enum<T>> String baseEnum2Str(T s) {
        if (s == null) {
            return null;
        }
        if (s instanceof BaseEnum) {
            return ((BaseEnum) s).getCode();
        }
        return Lambdas.apply(s, Enum::name);
    }

    static <T extends Enum<T>> T mapIntegerToEnum(Integer s, @TargetType Class<T> type) {
        if (s == null) {
            return null;
        }
        if (BasicEnum.class.isAssignableFrom(type)) {
            return BasicEnum.of(type, s);
        }
        return Lambdas.apply(s, v -> {
            CommonErrors.BAD_REQUEST.check(type.getEnumConstants().length > v);
            return type.getEnumConstants()[v];
        });
    }

    static <T extends Enum<T>> T mapStringToEnum(String s, @TargetType Class<T> type) {
        return Lambdas.apply(s, v -> Enum.valueOf(type, v));
    }

    static Long mapToId(IdNameDTO s) {
        return Lambdas.apply(s, IdNameDTO::getId);
    }

    static String mapToName(IdNameDTO s) {
        return Lambdas.apply(s, IdNameDTO::getName);
    }

    static <T extends Collection> Integer mapCollectionToSize(T s) {
        return Lambdas.apply(s, Collection::size);
    }

    static <T extends Map> Integer integerFromMap(T s) {
        return Lambdas.apply(s, Map::size);
    }

    static List<String> stringFromList(String s) {
        return Lambdas.apply(s, v -> Arrays.asList(v.split(",")));
    }

    static String listFromString(List<String> s) {
        return Lambdas.apply(s, v -> StringUtils.join(v, ","));
    }

    static Date localDate2Date(LocalDate date) {
        return Dates.localDate2Date(date);
    }

    static Date localDateTime2Date(LocalDateTime dateTime) {
        return Dates.localDateTime2Date(dateTime);
    }

    static Date localDateTime2Date(LocalDate dateTime) {
        return Dates.localDate2Date(dateTime);
    }

    static LocalDateTime str2LocalDateTime(String s) {
        if (StringUtils.isEmpty(s)) {
            return null;
        }
        return Dates.parseDateTime(s);
    }

    static LocalDateTime date2LocalDateTime(Date date) {
        if (Objects.isNull(date)) {
            return null;
        }
        return Dates.date2LocalDateTime(date);
    }

    static LocalDateTime long2LocalDateTime(Long timeStamp) {
        if (Objects.isNull(timeStamp)) {
            return null;
        }
        return Dates.long2LocalDateTime(timeStamp);
    }

    static LocalDate long2LocalDate(Long timeStamp) {
        if (Objects.isNull(timeStamp)) {
            return null;
        }
        return Dates.long2LocalDate(timeStamp);
    }

    static LocalDate str2LocalDate(String s) {
        if (StringUtils.isEmpty(s)) {
            return null;
        }
        return Dates.parseDate(s);
    }

    static LocalTime str2LocalTime(String s) {
        if (StringUtils.isEmpty(s)) {
            return null;
        }
        return Dates.parseTime(s);
    }

    static String localDateTime2Str(LocalDateTime s) {
        return Lambdas.apply(s, Dates::formatDateTime);
    }

    static String localDate2Str(LocalDate s) {
        return Lambdas.apply(s, Dates::formatDate);
    }

    static String localTime2Str(LocalTime s) {
        return Lambdas.apply(s, Dates::formatTime);
    }

}
